home *** CD-ROM | disk | FTP | other *** search
- //Date: Fri, 12 May 1995 13:17:33 -0500
- //From: cburke@mitre.org (Carl D. Burke)
- //Subject: blender -- driver entry for 4mile race
-
- /* Blender (blender(); blender.cpp)
- Carl Burke (cburke@mitre.org)
-
- This is a dynamic (reentrant) driver program for RARS. It's my third
- and so far most successful attempt. The first two tries were neural
- networks of various types, with learning supplied by a genetic algorithm.
- Neither did particularly well, although the second try got fairly decent
- speeds (and lots of damage). This program uses some concepts derived
- from developing the neural net drivers and some code from the TUT3 'bot;
- it's generally faster and takes less damage, but isn't yet in the same
- class as WappuCar, Indretti, or the latest Ramdu in short races. It does
- have some minimal passing behavior, but no memory; it tends to wiggle
- a lot in extended passing sequences on straightaways. Cars behind it
- are ignored; I leave it up to THEM to pass ME.
-
- The parameters were originally seeded with the TUT3 values, then allowed
- to drift with a genetic algorithm (single crossover, a small percentage
- of weights receiving +-5% mutations in each generation; 400 individuals
- in each generation, evaluated with 50 races of 8 drivers on each of
- 7 tracks; selecting for (1) pole position, (2) average speed, and (3)
- amount of damage at the end of the race). Since it takes a considerable
- amount of time to run a generation (currently 50 minutes on an SGI Indigo 2),
- only 50 generations were run before packaging the best set of parameters
- for the 4mile.trk endurance race.
-
- This 'bot has been tested with the Unix/X port of v0.5. It successfully
- completed 50 laps of fourmile.trk, beating the other two survivors (Rudy
- and the 0.39 Ramdu2) by 2 and 3 laps, respectively.
- I haven't tested this code on the PC, with or without the Borland compiler;
- I'm using the SGI ANSI C compiler, which should be compatible, but I don't
- know the code/data size.
- */
-
- #include <string.h>
- #include <stdlib.h>
- #include <math.h>
- #include "car.h"
- #include <stdio.h>
-
- #define NUM_RAD_CATS 32
- #define MAX_RAD_CAT (NUM_RAD_CATS-1)
- #define LEFT_TOO_CLOSE 0.1
- #define RIGHT_TOO_CLOSE 0.9
- #define VEL_INTERVAL 6
-
- float STEER_GAIN[] = {
- -0.48,-0.48,-0.52,-0.47,-0.50,-0.53,-0.50,-0.50,
- -0.50,-0.49,-0.54,-0.50,-0.52,-0.50,-0.47,-0.51,
- -0.51,-0.51,-0.50,-0.50,-0.54,-0.50,-0.49,-0.52,
- -0.46,-0.48,-0.52,-0.48,-0.46,-0.49,-0.49,-0.50
- };
- float DAMP_GAIN[] = {
- 2.00, 1.98, 2.05, 2.14, 1.92, 2.00, 2.07, 2.03,
- 2.00, 1.86, 2.10, 2.09, 2.00, 2.04, 2.18, 1.92,
- 2.05, 1.98, 1.96, 1.82, 1.95, 2.08, 2.03, 1.89,
- 1.98, 2.08, 1.98, 2.07, 1.98, 2.00, 2.01, 1.95
- };
- float VC[] = {
- 212.36, 9.38,15.76,26.20,42.40,85.23,130.42,203.04,
- 303.36,495.97,829.75,1400.22,2532.72,3857.52,5701.30,9898.29,
- 303.36,303.36,303.36,303.36,303.36,303.36,303.36,303.36,
- 303.36,303.36,303.36,303.36,303.36,303.36,303.36,303.36
- };
- float BIAS[] = {
- 0,0.0124815,0.00337826,0.000833944,0.000193107,
- 4.50358e-05,1.04967e-05,2.29944e-06,4.99283e-07,
- 1.18413e-07,2.54341e-08,5.77603e-09,1.30733e-09,
- 2.84956e-10,6.50293e-11,1.33113e-11,3.12386e-12,
- 7.20806e-13,1.55528e-13,3.45403e-14,7.89733e-15,
- 1.84584e-15,3.85515e-16,9.14617e-17,2.00144e-17,
- 4.34022e-18,9.77549e-19,2.20388e-19,4.98952e-20,
- 1.06157e-20,2.91439e-21,5.58335e-22
- };
- float LANE_RATIO[] = {
- 0.19, 0.18, 0.22, 0.20, 0.20, 0.20, 0.20, 0.20,
- 0.20, 0.21, 0.21, 0.20, 0.21, 0.19, 0.22, 0.21,
- 0.20, 0.20, 0.20, 0.20, 0.21, 0.20, 0.20, 0.21,
- 0.20, 0.18, 0.21, 0.20, 0.21, 0.20, 0.19, 0.19
- };
- float DIST_PARM[] = {
- 0.29, 0.24, 0.24, 0.25, 0.26, 0.25, 0.25, 0.25,
- 0.25, 0.25, 0.25, 0.27, 0.25, 0.25, 0.24, 0.28,
- 0.26, 0.25, 0.27, 0.26, 0.26, 0.24, 0.27, 0.24,
- 0.24, 0.26, 0.28, 0.25, 0.25, 0.28, 0.24, 0.25
- };
-
- con_vec Blender(situation& s)
- {
- const char name[] = "Blender"; // This is the robot driver's name!
- static int init_flag = 1; // cleared by first call
- con_vec result; // This is what is returned.
- double alpha, vc; // components of result
- double width;
-
- double lft_ratio, rgt_ratio;
- double vc_cur, vc_nex;
- double alpha_cur, alpha_nex, damp_gain, bias;
- double dist_parm;
- int collrisk_x[3], collrisk_y[3], coll_cnt;
- int i;
- float dval, dist_val, coll_vc, coll_alpha, colltime, pred_rely, pred_relx;
- float dist_val_after, vc_after;
- float turn_size;
-
- float v_int = s.v/VEL_INTERVAL;
- int lowv = (int)v_int;
- int highv = lowv+1;
- float lowv_wt = highv - v_int;
- float highv_wt = v_int - lowv;
-
- if (lowv < 0) lowv = 0;
- if (highv < 0) highv = 0;
- if (lowv > MAX_RAD_CAT) lowv = MAX_RAD_CAT;
- if (highv > MAX_RAD_CAT) highv = MAX_RAD_CAT;
- dist_parm = (lowv_wt*DIST_PARM[lowv] + highv_wt*DIST_PARM[highv]);
-
- if(init_flag == 1) { // first time only, copy name:
- my_name_is(name);
- init_flag = 0;
- result.alpha = result.vc = 0;
- return result;
- }
-
- // service routine in the host software to handle getting unstuck from
- // from crashes and pileups:
- if(stuck(s.backward, s.v,s.vn, s.to_lft,s.to_rgt, &result.alpha,&result.vc))
- return result;
-
- width = s.to_lft + s.to_rgt; // compute width of track
- lft_ratio = s.to_lft/width;
- rgt_ratio = s.to_rgt/width;
- // calculate alpha for current turn
- {
- float lane_ratio, steer_gain;
- if (s.cur_rad == 0.0)
- {
-
- // lane control for straightaway should be minimal; just keep it in
- // the road (check for "too close" to edge and steer away)
-
- lane_ratio = 0.0;
- if (lft_ratio < LEFT_TOO_CLOSE)
- {
- lane_ratio = LEFT_TOO_CLOSE - lft_ratio;
- }
- else if (lft_ratio > RIGHT_TOO_CLOSE)
- {
- lane_ratio = rgt_ratio - RIGHT_TOO_CLOSE;
- }
- steer_gain = STEER_GAIN[0];
- damp_gain = DAMP_GAIN[0];
- bias = 0.0;
- vc_cur = VC[0];
- dist_val = s.to_end;
- }
- else if (s.cur_rad > 0.0)
- {
- float ln_rad = log(s.cur_rad + s.to_lft);
- int low = 1 + (int)ln_rad;
- int high = low+1;
- float low_wt = high - ln_rad;
- float high_wt = ln_rad - low;
-
- if (low < 1) low = 1;
- if (high < 1) high = 1;
- if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
- if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
- lane_ratio = (low_wt*LANE_RATIO[low] + high_wt*LANE_RATIO[high])
- - lft_ratio;
- steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
- damp_gain = (low_wt*DAMP_GAIN[low] + high_wt*DAMP_GAIN[high]);
- bias = (low_wt*BIAS[low] + high_wt*BIAS[high]);
- vc_cur = (low_wt*VC[low] + high_wt*VC[high]);
- dist_val = s.to_end * s.cur_rad;
- }
- else if (s.cur_rad < 0.0)
- {
- float ln_rad;
- int low;
- int high;
- float low_wt;
- float high_wt;
- float radius_temp;
-
- radius_temp = -(s.cur_rad + s.to_rgt);
- ln_rad = log(-s.cur_rad + s.to_rgt);
- low = 1 + (int)ln_rad;
- high = low+1;
- low_wt = high - ln_rad;
- high_wt = ln_rad - low;
- if (low < 1) low = 1;
- if (high < 1) high = 1;
- if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
- if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
- lane_ratio = rgt_ratio - (low_wt*LANE_RATIO[low] +
- high_wt*LANE_RATIO[high]);
- steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
- damp_gain = (low_wt*DAMP_GAIN[low] + high_wt*DAMP_GAIN[high]);
- bias = -(low_wt*BIAS[low] + high_wt*BIAS[high]);
- vc_cur = (low_wt*VC[low] + high_wt*VC[high]);
- dist_val = -s.to_end * s.cur_rad;
- }
- alpha_cur = steer_gain * lane_ratio;
- }
-
- // calculate alpha for following turn
- {
- float lane_ratio, steer_gain;
- if (s.nex_rad == 0.0)
- {
- // should try to use lane_ratio for following turn if close enough
- // lane control for straightaway should be minimal; just keep it in
- // the road (check for "too close" to edge and steer away)
-
- lane_ratio = 0.0;
- if (lft_ratio < LEFT_TOO_CLOSE)
- {
- lane_ratio = LEFT_TOO_CLOSE - lft_ratio;
- }
- else if (lft_ratio > RIGHT_TOO_CLOSE)
- {
- lane_ratio = rgt_ratio - RIGHT_TOO_CLOSE;
- }
- steer_gain = STEER_GAIN[0];
- vc_nex = VC[0];
- dist_val_after = s.nex_len;
- turn_size = 1.0;
- }
- else if (s.nex_rad > 0.0)
- {
- float ln_rad = log(s.nex_rad);
- int low = (int)ln_rad;
- int high = low+1;
- float low_wt = high - ln_rad;
- float high_wt = ln_rad - low;
-
- if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
- if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
- lane_ratio = (low_wt*LANE_RATIO[low] + high_wt*LANE_RATIO[high])
- - lft_ratio;
- steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
- vc_nex = (low_wt*VC[low] + high_wt*VC[high]);
- dist_val_after = s.nex_len * s.nex_rad;
- turn_size = (fabs(s.nex_rad) -
- fabs(cos(s.nex_len)*s.nex_rad))/(.75*width);
- // adjust calculated size in case turn > 90 degrees
- if (fabs(s.nex_len) > 1.5) turn_size = 1.0;
- }
- else if (s.nex_rad < 0.0)
- {
- float ln_rad = log(-s.nex_rad);
- int low = (int)ln_rad;
- int high = low+1;
- float low_wt = high - ln_rad;
- float high_wt = ln_rad - low;
-
- if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
- if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
- lane_ratio = rgt_ratio - (low_wt*LANE_RATIO[low] +
- high_wt*LANE_RATIO[high]);
- steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
- vc_nex = (low_wt*VC[low] + high_wt*VC[high]);
- dist_val_after = -s.nex_len * s.nex_rad;
- turn_size = (fabs(s.nex_rad) -
- fabs(cos(s.nex_len)*s.nex_rad))/(.75*width);
- // adjust calculated size in case turn > 90 degrees
- if (fabs(s.nex_len) > 1.5) turn_size = 1.0;
- }
- alpha_nex = steer_gain * lane_ratio;
- }
- // calculate vc for second turn ahead
- {
- if (s.after_rad == 0.0)
- {
- vc_after = VC[0];
- }
- else if (s.after_rad > 0.0)
- {
- float ln_rad = log(s.after_rad);
- int low = (int)ln_rad;
- int high = low+1;
- float low_wt = high - ln_rad;
- float high_wt = ln_rad - low;
-
- if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
- if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
- vc_after = (low_wt*VC[low] + high_wt*VC[high]);
- if (s.nex_rad == 0.0)
- {
- float lane_ratio, steer_gain;
- lane_ratio = (low_wt*LANE_RATIO[low] +
- high_wt*LANE_RATIO[high]) - lft_ratio;
- steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
- alpha_nex = steer_gain * lane_ratio;
- }
- }
- else if (s.after_rad < 0.0)
- {
- float ln_rad = log(-s.after_rad);
- int low = (int)ln_rad;
- int high = low+1;
- float low_wt = high - ln_rad;
- float high_wt = ln_rad - low;
-
- if (low > MAX_RAD_CAT) low = MAX_RAD_CAT;
- if (high > MAX_RAD_CAT) high = MAX_RAD_CAT;
- vc_after = (low_wt*VC[low] + high_wt*VC[high]);
- if (s.nex_rad == 0.0)
- {
- float lane_ratio, steer_gain;
- lane_ratio = rgt_ratio - (low_wt*LANE_RATIO[low] +
- high_wt*LANE_RATIO[high]);
- steer_gain = (low_wt*STEER_GAIN[low] + high_wt*STEER_GAIN[high]);
- alpha_nex = steer_gain * lane_ratio;
- }
- }
- }
-
- // Blend values for current and next based on speed/distance ratio
- // vc is calculated without regard for power requirements or loss of traction;
- // this should probably change in the future
- // look ahead to second turn; if too far to care, then look at next turn.
- // second lookahead only for speed adjustment, not for turning (so far)
- // also adjust dval for nearest turn -- some turns are too short and
- // too shallow to require much adjustment to speed. (keep alpha normal)
-
- if (turn_size > 1.0) turn_size = 1.0;
- if (s.v < 0.001) dval = 1.0;
- else dval = (dist_parm * (dist_val + dist_val_after)/s.v);
- if ((dval >= 1.0) || (vc_nex < vc_after))
- {
- if (s.v < 0.001) dval = 1.0;
- else dval = (dist_parm * dist_val/s.v);
- }
- else
- {
- vc_nex = vc_after;
- }
- dval = dval*dval; // attempt to correct offtrack at end of high-speed sections
- if (dval < 0.0) dval = 0.0;
- if (dval > 1.0) dval = 1.0;
- alpha = (dval * alpha_cur + (1 - dval) * alpha_nex)
- - damp_gain * s.vn/s.v + s.v*s.v*bias;
- dval = dval/turn_size; // scale importance of next turn by size
- if (dval < 0.0) dval = 0.0;
- if (dval > 1.0) dval = 1.0;
- vc = dval * vc_cur + (1 - dval) * vc_nex;
-
- // these are nominal values based on track following. now need to look
- // at other cars to see if there's a collision risk and modify the values
- // accordingly.
-
- coll_cnt = 0;
- coll_alpha = 0;
- coll_vc = vc;
- for (i=0;i<3;i++)
- {
- if (s.nearby[i].who > 16) continue;
- if (s.nearby[i].rel_y < 0.0) continue; // don't worry about those behind
- collrisk_x[i] = 0; // no collision risk with this vehicle
- collrisk_y[i] = 0;
-
- if (((s.nearby[i].rel_x > 0 && s.nearby[i].rel_xdot < 0) ||
- (s.nearby[i].rel_x < 0 && s.nearby[i].rel_xdot > 0)) &&
- (fabs(s.nearby[i].rel_xdot) > 0.01))
- {
- // vehicles are closing the x distance
- collrisk_x[i] = 1;
- }
- if (((s.nearby[i].rel_y > 0 && s.nearby[i].rel_ydot < 0) ||
- (s.nearby[i].rel_y < 0 && s.nearby[i].rel_ydot > 0)) &&
- (fabs(s.nearby[i].rel_ydot) > 0.01))
- {
- // vehicles are closing the y distance
- collrisk_y[i] = 1;
- }
- // if no convergence, then no chance of collision
- if (collrisk_x[i] == 0 && collrisk_y[i] == 0) continue;
- // there's some chance of collision with this vehicle
- // try to calculate better odds and timing
- // look at x-axis first
- if (collrisk_x[i])
- {
- colltime =
- (fabs(s.nearby[i].rel_x)-CARWID)/fabs(s.nearby[i].rel_xdot);
- if (colltime < 2.0) // less than 2 seconds to react
- {
- // what will the rely be at colltime?
- pred_rely = s.nearby[i].rel_y + s.nearby[i].rel_ydot * colltime;
- if (fabs(pred_rely) < CARLEN) // within a carlength?
- {
- coll_cnt++;
- if (s.cur_rad == 0) // straightaway
- {
- if (s.nex_rad > 0.0)
- {
- if (lft_ratio < LEFT_TOO_CLOSE)
- {
- coll_vc = 0.95 * s.v;
- coll_alpha += 0.0;
- }
- else
- {
- if (s.nearby[i].rel_x > 0.0)
- {coll_vc = 0.95 * s.v;}
- coll_alpha += (3.141592/18.0);
- }
- }
- else
- {
- if (lft_ratio > RIGHT_TOO_CLOSE)
- {
- coll_vc = 0.95 * s.v;
- coll_alpha += 0.0;
- }
- else
- {
- if (s.nearby[i].rel_x < 0.0)
- {coll_vc = 0.95 * s.v;}
- coll_alpha -= (3.141592/18.0);
- } }
- }
- else if (s.cur_rad > 0.0) // left turn
- {
- if (s.nearby[i].rel_x < 0.0)
- {
- coll_vc = 0.95 * s.v;
- coll_alpha -= (3.141592/18.0);
- }
- else
- {coll_alpha += (3.141592/18.0);}
- }
- else // (s.cur_rad < 0.0) // right turn
- {
- if (s.nearby[i].rel_x > 0.0)
- {
- coll_vc = 0.95 * s.v;
- coll_alpha += (3.141592/18.0);
- }
- else
- {coll_alpha -= (3.141592/18.0);}
- }
- }
- }
- }
- if (collrisk_y[i])
- {
- colltime =
- (fabs(s.nearby[i].rel_y)-CARLEN)/fabs(s.nearby[i].rel_ydot);
- if (colltime < 2.0) // less than 2 seconds to react
- {
- // what will the relx be at colltime?
- pred_relx = s.nearby[i].rel_x + s.nearby[i].rel_xdot * colltime;
- if (fabs(pred_relx) < CARWID) // within a carwidth?
- {
- coll_cnt++;
- if (s.cur_rad == 0) // straightaway
- {
- if (s.nex_rad > 0.0)
- {
- if (lft_ratio < LEFT_TOO_CLOSE)
- {
- coll_vc = 0.95 * s.v;
- coll_alpha += 0.0;
- }
- else
- {
- if (s.nearby[i].rel_x > 0.0)
- {coll_vc = 0.95 * s.v;}
- coll_alpha += (3.141592/18.0);
- }
- }
- else
- {
- if (lft_ratio > RIGHT_TOO_CLOSE)
- {
- coll_vc = 0.95 * s.v;
- coll_alpha += 0.0;
- }
- else
- {
- if (s.nearby[i].rel_x < 0.0)
- {coll_vc = 0.95 * s.v;}
- coll_alpha -= (3.141592/18.0);
- } }
- }
- else if (s.cur_rad > 0.0) // left turn
- {
- if (s.nearby[i].rel_x <= 0.0)
- {
- coll_vc = 0.95 * s.v;
- coll_alpha -= (3.141592/18.0);
- }
- else
- {coll_alpha += (3.141592/18.0);}
- }
- else // (s.cur_rad < 0.0) // right turn
- {
- if (s.nearby[i].rel_x > 0.0)
- {
- coll_vc = 0.95 * s.v;
- coll_alpha += (3.141592/18.0);
- }
- else
- {coll_alpha -= (3.141592/18.0);}
- }
- }
- }
- }
- }
- if (coll_cnt > 0)
- {
- coll_alpha /= (double)coll_cnt;
- }
- result.vc = coll_vc; result.alpha = alpha+coll_alpha;
- return result;
- }
-
-
-
-